package com.randi.generator.service.impl;

import com.randi.generator.entity.GenTable;
import com.randi.generator.entity.GenTableColumn;
import com.randi.generator.mapper.GenTableMapper;
import com.randi.generator.service.IDbTableService;
import com.randi.generator.service.IGenTableColumnService;
import com.randi.generator.service.IGenTableService;
import com.randi.generator.util.VelocityInitializer;
import com.randi.generator.util.VelocityUtils;
import org.apache.commons.io.IOUtils;
import org.apache.velocity.Template;
import org.apache.velocity.VelocityContext;
import org.apache.velocity.app.Velocity;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.StringWriter;
import java.util.*;
import java.util.regex.Pattern;
import java.util.zip.ZipEntry;
import java.util.zip.ZipOutputStream;

@Service
public class GenTableService implements IGenTableService {

    @Resource
    private GenTableMapper genTableMapper;

    @Resource
    private IGenTableColumnService iGenTableColumnService;

    @Resource
    private IDbTableService iDbTableService;

    /**
     * 查询业务列表
     *
     * @return 业务集合
     */
    @Override
    public List<GenTable> selectGenTableList(GenTable genTable) {
        return genTableMapper.selectGenTableList(genTable);
    }

    /**
     * 查看详情
     *
     * @return 业务集合
     */
    @Override
    public GenTable selectGenTableById(Long tableId) {
        return genTableMapper.selectGenTableById(tableId);
    }

    /**
     * 导入数据
     *
     * @param tableNames tableNames
     * @return 结果
     */
    @Override
    @Transactional
    public int importGenTable(String[] tableNames) {
        int num = 0;

        Date date = new Date();
        List<GenTable> genTables = iDbTableService.selectDbTableListByTableNames(tableNames);
        for (GenTable genTable : genTables) {
            // 插入数据表
            genTable.setCreateTime(date);
            int status = genTableMapper.insert(genTable);
            if (status == 0) {
                continue;
            }
            // 插入字段
            List<GenTableColumn> genTableColumns = iDbTableService.selectDbTableColumnsByTableName(genTable.getTableName());
            for (GenTableColumn column : genTableColumns) {
                column.setTableId(genTable.getTableId());
                iGenTableColumnService.insertGenTableColumn(column);
            }
            num++;
        }

        return num;
    }

    /**
     * 更新数据
     *
     * @param genTable GenTable
     * @return 结果
     */
    @Override
    public int updateGenTable(GenTable genTable) {
        genTable.setUpdateTime(new Date());

        int status = genTableMapper.updateById(genTable);

        for (GenTableColumn column : genTable.getColumns()) {
            column.setTableId(genTable.getTableId());
            iGenTableColumnService.updateGenTableColumn(column);
        }

        return status;
    }

    /**
     * 删除数据
     *
     * @param tableId tableId
     * @return 结果
     */
    @Override
    @Transactional
    public int deleteGenTable(Long tableId) {
        iGenTableColumnService.deleteGenTableColumnByTableId(tableId);
        return genTableMapper.deleteById(tableId);
    }

    /**
     * 批量删除数据
     *
     * @param tableIds tableIds
     * @return status
     */
    @Override
    public int deleteBatchGenTable(List<Long> tableIds) {
        iGenTableColumnService.deleteBatchByTableIds(tableIds);
        return genTableMapper.deleteBatchIds(tableIds);
    }

    /**
     * 格式化-删除多余回车
     *
     * @param code 代码
     * @return 结果
     */
    private String codeFormat(String code) {
        return Pattern.compile("\n(\\s*\r?\n){2,}").matcher(code).replaceAll("\n");
    }

    /**
     * 预览代码
     *
     * @param tableId tableId
     * @return codeMap
     */
    public Map<String, String> previewCode(Long tableId) {
        Map<String, String> codeMap = new LinkedHashMap<>();
        // 查询表信息
        GenTable genTable = genTableMapper.selectGenTableById(tableId);

        VelocityInitializer.initVelocity();
        // 设置模板参数
        VelocityContext context = VelocityUtils.prepareContext(genTable);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList();
        for (String template : templates) {
            // 渲染模板
            StringWriter stringWriter = new StringWriter();
            Template tpl = Velocity.getTemplate(template, "UTF-8");
            tpl.merge(context, stringWriter);

            codeMap.put(template, codeFormat(stringWriter.toString()));
        }

        return codeMap;
    }

    /**
     * 生成代码
     *
     * @param tableId tableId
     * @return Result
     */
    @Override
    public byte[] downloadCode(Long tableId) {
        ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
        ZipOutputStream zipOutputStream = new ZipOutputStream(outputStream);
        generatorCode(tableId, zipOutputStream);
        IOUtils.closeQuietly(zipOutputStream);
        return outputStream.toByteArray();
    }

    /**
     * 查询表信息并生成代码
     *
     * @param tableId         tableId
     * @param zipOutputStream zipOutputStream
     */
    private void generatorCode(Long tableId, ZipOutputStream zipOutputStream) {
        GenTable genTable = genTableMapper.selectGenTableById(tableId);

        VelocityInitializer.initVelocity();
        VelocityContext context = VelocityUtils.prepareContext(genTable);

        // 获取模板列表
        List<String> templates = VelocityUtils.getTemplateList();
        for (String template : templates) {
            // 渲染模板
            StringWriter stringWriter = new StringWriter();
            Velocity.getTemplate(template, "UTF-8").merge(context, stringWriter);

            try {
                // 添加zip
                zipOutputStream.putNextEntry(new ZipEntry(VelocityUtils.getFileName(template, genTable)));

                // 写入文件
                IOUtils.write(codeFormat(stringWriter.toString()), zipOutputStream, "UTF-8");
                IOUtils.closeQuietly(stringWriter);
                zipOutputStream.flush();
                zipOutputStream.closeEntry();
            } catch (IOException e) {
                throw new SecurityException("渲染模板失败，表名：" + genTable.getTableName());
            }
        }
    }

}
